package com.zb.finance.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.zb.constant.FinanceConstant;
import com.zb.constant.RedisConstant;
import com.zb.constant.WorkConstant;
import com.zb.entity.*;
import com.zb.excel.WithdrawExcelVo;
import com.zb.exception.NoAuthPayException;
import com.zb.extend.WithdrawExtend;
import com.zb.extend.WorkOrderExtend;
import com.zb.finance.service.ConWithdrawService;
import com.zb.mobile.NetworkOrderRecordSearchVo;
import com.zb.mobile.NetworkWithdrawOrderDetailVo;
import com.zb.mobile.NetworkWithdrawOrderListVo;
import com.zb.result.PageUtil;
import com.zb.service.*;
import com.zb.service.impl.FinanceLogService;
import com.zb.service.impl.WorkServiceLog;
import com.zb.utils.ZbManager;
import com.zb.utils.ZbOrderNoUtil;
import com.zb.view.ViewNetworkEmpAccount;
import com.zb.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author WEN
 * @Date 2024/5/28 0028
 **/
@Slf4j
@Service
public class ConWithdrawServiceImpl implements ConWithdrawService {
    @Resource
    private ZjWorkOrderService workOrderService;
    @Resource
    private ZjWithdrawService withdrawService;
    @Resource
    private ZjWithdrawOrderService withdrawOrderService;
    @Resource
    private ZjNetworkService networkService;
    @Resource
    private ZjWithdrawCheckEmpService withdrawCheckEmpService;
    @Resource
    private ZjWithdrawVoucherService withdrawVoucherService;
    @Resource
    private ViewNetworkEmpAccountService viewNetworkEmpAccountService;
    @Resource
    private ZjWorkUserService workUserService;
    @Resource
    private ZjWorkModuleService workModuleService;
    @Resource
    private ZjWithdrawSetService withdrawSetService;
    @Resource
    private ZjWithdrawRecordService zjWithdrawRecordService;

    // 获取可提现工单列表
    @Override
    public Map<String, Object> getWithdrawOrderList(Long networkId, Long networkEmpId, PageUtil pageUtil) {
        NetworkOrderRecordSearchVo search = new NetworkOrderRecordSearchVo();
        search.setStatus(1);
        search.setPage(pageUtil.getPage());
        search.setLimit(pageUtil.getLimit());
        long count = workOrderService.getWithdrawOrderListCount(networkId, networkEmpId, search);
        if (count <= 0) {
            return PageUtil.pageList(search.getPage(), search.getLimit(), count, new ArrayList<>());
        }
        List<WorkOrderExtend> orderList = workOrderService.getWithdrawOrderList(networkId, networkEmpId, search);
        // 查询服务费、配件费
        List<OrderSettlementPriceVo> settlementPriceVoList = workOrderService.getOrderSettlementPriceByWorkId(orderList.stream().map(ZjWorkOrder::getId).toList());
        // 查询工程师
        List<ViewNetworkEmpAccount> networkEmpAccountList = viewNetworkEmpAccountService.getByIds(orderList.stream().map(WorkOrderExtend::getNetworkEmpId).distinct().toList());
        List<NetworkWithdrawOrderListVo> withdrawOrderListVoList = new ArrayList<>();
        NetworkWithdrawOrderListVo withdrawOrderListVo = null;
        ViewNetworkEmpAccount viewNetworkEmpAccount = null;
        for (WorkOrderExtend order : orderList) {
            withdrawOrderListVo = new NetworkWithdrawOrderListVo();
            withdrawOrderListVo.setId(order.getId());
            withdrawOrderListVo.setWorkNo(order.getCode());
            withdrawOrderListVo.setEndTime(order.getEndTime());
            withdrawOrderListVo.setTotalPrice(order.getNetworkModulePrice().add(settlementPriceVoList.stream().filter(f -> Objects.equals(f.getWorkId(), order.getId())).findFirst()
                    .map(OrderSettlementPriceVo::getPayNetworkPrice).orElse(new BigDecimal("0.0"))).subtract(order.getNetworkSettlementDeductionPrice()));
            withdrawOrderListVo.setUsername(order.getUserName());
            withdrawOrderListVo.setUsePhone(order.getUserPhone());
            viewNetworkEmpAccount = networkEmpAccountList.stream().filter(f -> Objects.equals(f.getId(), order.getNetworkEmpId())).findFirst().orElse(null);
            if (null != viewNetworkEmpAccount) {
                withdrawOrderListVo.setEngineer(viewNetworkEmpAccount.getName());
                withdrawOrderListVo.setEngineerPhone(viewNetworkEmpAccount.getPhone());
            }
            withdrawOrderListVoList.add(withdrawOrderListVo);
        }
        return PageUtil.pageList(search.getPage(), search.getLimit(), count, withdrawOrderListVoList);
    }

    // 保存提现单
    @Override
    @Transactional
    public synchronized void save(AccounLoginInfo loginInfo, WithdrawVo withdrawVo) {
        if (null == withdrawVo.getId()) {
            // 查询提现金额是否达到最低限制
            BigDecimal totalMoney = withdrawVo.getOrderVos().stream().map(WithdrawOrderVo::getWithdrawMoney).reduce(BigDecimal::add).orElse(new BigDecimal("0.0"));
            // 查询设置
            ZjWithdrawSet withdrawSet = withdrawSetService.getById(loginInfo.getCustAccId());
            if (totalMoney.floatValue() < withdrawSet.getMinWithdrawMoney().floatValue()) {
                Assert.isTrue(false, "提现金额低于提现设置的最低提现金额，不允许提现");
            }
            // 查询工单是否存在重复提现
            List<Long> workIds = withdrawVo.getOrderVos().stream().map(WithdrawOrderVo::getWorkId).toList();
            QueryWrapper<ZjWithdrawOrder> withdrawOrderQueryWrapper = new QueryWrapper<>();
            withdrawOrderQueryWrapper.select("id", "work_id", "work_no")
                    .in("work_id", workIds);
            List<ZjWithdrawOrder> withdrawOrders = withdrawOrderService.list(withdrawOrderQueryWrapper);
            List<String> workNos = withdrawVo.getOrderVos().stream().filter(f -> withdrawOrders.stream().anyMatch(f2 -> Objects.equals(f2.getWorkId(), f.getWorkId()))).map(WithdrawOrderVo::getWorkNo).toList();
            Assert.isTrue(CollectionUtil.isEmpty(withdrawOrders), "存在重复提现的工单，工单号：" + String.join("、", workNos));

            QueryWrapper<ZjWorkOrder> orderQueryWrapper = new QueryWrapper<>();
            orderQueryWrapper.select("id", "code", "settlement_status")
                    .in("id", withdrawVo.getOrderVos().stream().map(WithdrawOrderVo::getWorkId).toList());
            List<ZjWorkOrder> orders = workOrderService.list(orderQueryWrapper);
            workNos = withdrawVo.getOrderVos().stream().filter(f -> orders.stream().noneMatch(f2 -> Objects.equals(f2.getId(), f.getWorkId()))).map(WithdrawOrderVo::getWorkNo).toList();
            Assert.isTrue(CollectionUtil.isEmpty(workNos), "无效的工单单号：" + String.join("、", workNos));

            workNos = orders.stream().filter(f -> f.getSettlementStatus() == WorkConstant.WORK_SETTLEMENT_STATUS_2 ||
                    f.getSettlementStatus() == WorkConstant.WORK_SETTLEMENT_STATUS_3).map(ZjWorkOrder::getCode).toList();
            Assert.isTrue(CollectionUtil.isEmpty(workNos), "提现单存在结算中的工单号：" + String.join("、", workNos));
        }
        ZjWithdraw withdraw = new ZjWithdraw();
        BeanUtil.copyProperties(withdrawVo, withdraw);
        withdraw.setBankCode(withdrawVo.getBankCode());
        withdraw.setOpenAccountBankNetwork(withdrawVo.getOpenAccountBankNetwork());
        String event = "新增申请提现单";
        if (null != withdraw.getId()) {
            event = "修改提现单";
            withdrawService.updateById(withdraw);
        } else {
            withdraw.setId(IdWorker.getId());
            withdraw.setCustAccId(loginInfo.getCustAccId());
            withdraw.setCode(ZbOrderNoUtil.financeWithdrawNo(loginInfo.getCustAccId()));
            withdraw.setStatus(FinanceConstant.WITHDRAW_STATUS_1);
            withdraw.setCheckEmpId(0L);
            withdraw.setCheckEmp("");
            withdraw.setCheckRemark("");
            withdrawService.save(withdraw);
        }
        List<ZjWorkOrder> updateOrderList = new ArrayList<>();
        ZjWorkOrder updateOrder = null;
        for (WithdrawOrderVo orderVo : withdrawVo.getOrderVos()) {
            updateOrder = new ZjWorkOrder();
            updateOrder.setId(orderVo.getWorkId());
            updateOrder.setSettlementStatus(WorkConstant.WORK_SETTLEMENT_STATUS_2);
            updateOrderList.add(updateOrder);
        }
        workOrderService.updateBatchById(updateOrderList);
        withdrawOrderService.save(loginInfo.getCustAccId(), withdraw.getId(), withdrawVo.getOrderVos());
        FinanceLogService.saveServiceWithdrawLog(new WithdrawLogVo(loginInfo.getCustAccId(), withdraw.getId(), loginInfo.getName(),
                networkService.getNameById(withdraw.getApplyNetworkId()), event, "平台代提现；备注：" + withdraw.getApplyRemark()));
    }

    // 获取提现单列表
    @Override
    public Map<String, Object> getList(Long custAccId, WithdrawListSearchVo search) {
        PageUtil.setPageLimit(search);
        long count = withdrawService.getListCount(custAccId, search);
        if (count <= 0) {
            return PageUtil.pageList(search.getPage(), search.getLimit(), count, new ArrayList<>());
        }
        List<WithdrawExtend> withdrawExtends = withdrawService.getList(custAccId, search);
        List<ZjNetwork> networkList = networkService.getNameByIds(withdrawExtends.stream().map(WithdrawExtend::getApplyNetworkId).distinct().toList());
        // 查询工程师
        List<Long> networkEmpIds = withdrawExtends.stream().map(WithdrawExtend::getApplyNetworkEmpId).distinct().toList();
        List<ViewNetworkEmpAccount> networkEmpAccountList = viewNetworkEmpAccountService.getByIds(networkEmpIds);
        return PageUtil.pageList(search.getPage(), search.getLimit(), count, withdrawExtends.stream().map(withdraw -> {
            WithdrawListVo vo = new WithdrawListVo();
            BeanUtil.copyProperties(withdraw, vo);
            vo.setApplyNetworkEmpPhone(networkEmpAccountList.stream().filter(f -> Objects.equals(f.getId(), withdraw.getApplyNetworkEmpId())).findFirst().map(ViewNetworkEmpAccount::getPhone).orElse(""));
            vo.setCreateTime(withdraw.getGmtCreate());
            ZjWithdrawRecord recordServiceById = zjWithdrawRecordService.getById(withdraw.getId());
            if (recordServiceById!=null)vo.setFailReason(recordServiceById.getCallbackResult());
            if (StringUtils.isNotBlank(withdraw.getWorkIdStr())) {
                vo.setWorkId(Arrays.stream(withdraw.getWorkIdStr().split(",")).map(Long::parseLong).distinct().toList());
            }
            if (StringUtils.isNotBlank(withdraw.getWorkNoStr())) {
                vo.setWorkNo(new ArrayList<>(Arrays.asList(withdraw.getWorkNoStr().split(","))).stream().distinct().toList());
            }
            vo.setNetwork(networkList.stream().filter(f -> Objects.equals(f.getId(), withdraw.getApplyNetworkId())).findFirst().map(ZjNetwork::getName).orElse(""));
            return vo;
        }).toList());
    }

    // 获取提现单详情
    @Override
    public WithdrawDetail getDetail(Long id) {
        ZjWithdraw withdraw = withdrawService.getById(id);
        Assert.notNull(withdraw, "查无此提现单：" + id);
        WithdrawDetail detail = new WithdrawDetail();
        BeanUtil.copyProperties(withdraw, detail);
        detail.setCreateTime(withdraw.getGmtCreate());
        detail.setPaths(withdrawVoucherService.getByWithdrawId(id));
        ViewNetworkEmpAccount empAccount = viewNetworkEmpAccountService.getById(withdraw.getApplyNetworkEmpId());
        detail.setApplyNetworkEmpPhone(null == empAccount? "" : empAccount.getPhone());
        return detail;
    }

    // 根据提现单ID获取提现工单
    @Override
    public Object getWithdrawOrder(Long withdrawId) {
        QueryWrapper<ZjWithdrawOrder> withdrawOrderQueryWrapper = new QueryWrapper<>();
        withdrawOrderQueryWrapper.select("id", "work_id", "work_no", "old_withdraw_money", "withdraw_money")
                .eq("withdraw_id", withdrawId);
        List<ZjWithdrawOrder> withdrawOrderList = withdrawOrderService.list(withdrawOrderQueryWrapper);
        List<Long> workIds = withdrawOrderList.stream().map(ZjWithdrawOrder::getWorkId).toList();
        Map<String, List<String>> engineerMap = new HashMap<>();
        List<ZjWorkUser> userList = new ArrayList<>();
        Map<String, String> workModuleMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(workIds)) {
            QueryWrapper<ZjWorkOrder> orderQueryWrapper = new QueryWrapper<>();
            orderQueryWrapper.select("id", "network_emp_id")
                    .in("id", workIds);
            List<ZjWorkOrder> orderList = workOrderService.list(orderQueryWrapper);
            List<Long> networkEmpIds = orderList.stream().map(ZjWorkOrder::getNetworkEmpId).distinct().toList();
            if (CollectionUtil.isNotEmpty(networkEmpIds)) {
                List<ViewNetworkEmpAccount> accountList = viewNetworkEmpAccountService.getByIds(networkEmpIds);
                ViewNetworkEmpAccount empAccount = null;
                List<String> emps = null;
                for (ZjWorkOrder order : orderList) {
                    empAccount = accountList.stream().filter(f -> Objects.equals(f.getId(), order.getNetworkEmpId())).findFirst().orElse(null);
                    if (null != empAccount) {
                        emps = new ArrayList<>();
                        emps.add(empAccount.getName());
                        emps.add(empAccount.getPhone());
                        engineerMap.put(order.getId().toString(), emps);
                    }
                }
                QueryWrapper<ZjWorkUser> workUserQueryWrapper = new QueryWrapper<>();
                workUserQueryWrapper.select("id", "name", "phone")
                        .in("id", workIds);
                userList.addAll(workUserService.list(workUserQueryWrapper));
            }
            // 获取工单模块类型
            List<Long> moduleIds = orderList.stream().map(ZjWorkOrder::getModuleId).distinct().toList();
            List<ZjWorkModule> moduleList = workModuleService.getPartInfoByIds(moduleIds);
            ZjWorkModule module = null;
            for (ZjWorkOrder order : orderList) {
                module = moduleList.stream().filter(f -> Objects.equals(f.getId(), order.getModuleId())).findFirst().orElse(null);
                workModuleMap.put(order.getId().toString(), null == module? "" : module.getName());
            }
        }
        List<NetworkWithdrawOrderDetailVo> withdrawOrderDetailVos = withdrawOrderList.stream().map(withdrawOrder -> {
            NetworkWithdrawOrderDetailVo vo = new NetworkWithdrawOrderDetailVo();
            vo.setId(withdrawOrder.getId());
            vo.setWorkId(withdrawOrder.getWorkId());
            vo.setWorkNo(withdrawOrder.getWorkNo());
            vo.setModule(workModuleMap.get(withdrawOrder.getWorkId().toString()));
            vo.setWithdrawMoney(withdrawOrder.getWithdrawMoney());
            vo.setOldWithdrawMoney(withdrawOrder.getOldWithdrawMoney());
            List<String> emps = engineerMap.get(withdrawOrder.getWorkId().toString());
            if (CollectionUtil.isNotEmpty(emps)) {
                vo.setEngineer(emps.get(0));
                vo.setEngineerPhone(emps.get(1));
            }
            userList.stream().filter(f -> Objects.equals(f.getId(), withdrawOrder.getWorkId())).findFirst().ifPresent(user -> {
                vo.setUsername(user.getName());
                vo.setUserPhone(user.getPhone());
            });
            return vo;
        }).toList();
        return withdrawOrderDetailVos;
    }

    // 审核提现单
    @Override
    @Transactional
    public void checkWithdraw(AccounLoginInfo loginInfo, CheckWithdrawVo withdrawVo) {
        // 校验审核人权限
        Assert.notNull(withdrawCheckEmpService.hasCheckAuthorByCustAccIdAndEmpId(loginInfo.getCustAccId(), loginInfo.getId()), "您没有审核提现单的权限");

        List<ZjWithdraw> withdraws = withdrawService.listByIds(withdrawVo.getIds());
        Assert.notEmpty(withdraws, "审核的提现单不存在：" + withdrawVo.getIds().stream().map(id -> {
            return id.toString();
        }).collect(Collectors.joining("、")));
        List<String> codes = withdraws.stream().filter(f -> f.getStatus() == FinanceConstant.WITHDRAW_STATUS_2).map(ZjWithdraw::getCode).toList();
        Assert.isTrue(CollectionUtil.isEmpty(codes), "当前提现单处于等待打款状态，不允许重复审核：" + String.join("、", codes));
        codes = withdraws.stream().filter(f -> f.getStatus() == FinanceConstant.WITHDRAW_STATUS_3).map(ZjWithdraw::getCode).toList();
        Assert.isTrue(CollectionUtil.isEmpty(codes), "当前提现单已打款完成，不允许重复审核：" + String.join("、", codes));
        codes = withdraws.stream().filter(f -> f.getStatus() == FinanceConstant.WITHDRAW_STATUS_4).map(ZjWithdraw::getCode).toList();
        Assert.isTrue(CollectionUtil.isEmpty(codes), "当前提现单提现失败，不允许重复审核：" + String.join("、", codes));
        codes = withdraws.stream().filter(f -> f.getStatus() == FinanceConstant.WITHDRAW_STATUS_5).map(ZjWithdraw::getCode).toList();
        Assert.isTrue(CollectionUtil.isEmpty(codes), "当前提现单已驳回，不允许重复审核：" + String.join("、", codes));
        // 查询申请人所属的服务商
        List<ZjNetwork> networkList = networkService.getNameByIds(withdraws.stream().map(ZjWithdraw::getApplyNetworkId).distinct().toList());

        List<ZjWithdraw> updateWithdraws = new ArrayList<>();
        ZjWithdraw updateWithdraw = null;
        List<WithdrawLogVo> withdrawLogVos = new ArrayList<>();
        for (ZjWithdraw withdraw : withdraws) {
            updateWithdraw = new ZjWithdraw();
            updateWithdraw.setId(withdraw.getId());
            updateWithdraw.setStatus(withdrawVo.getResult() == 1? FinanceConstant.WITHDRAW_STATUS_2 : FinanceConstant.WITHDRAW_STATUS_5);
            updateWithdraw.setCheckEmpId(loginInfo.getId());
            updateWithdraw.setCheckEmp(loginInfo.getName());
            updateWithdraw.setCheckTime(new Date());
            updateWithdraw.setCheckRemark(withdrawVo.getCheckRemark());
            updateWithdraws.add(updateWithdraw);
            withdrawLogVos.add(new WithdrawLogVo(loginInfo.getCustAccId(), withdraw.getId(), loginInfo.getName(),
                    networkList.stream().filter(f -> Objects.equals(f.getId(), withdraw.getApplyNetworkId())).map(ZjNetwork::getName).findFirst().orElse(""),
                    "审核提现",
                    (withdrawVo.getResult() == 1 ? "审核结果：已通过，等待打款；备注：" : "审核结果：已驳回；备注：") +
                    withdrawVo.getCheckRemark()));
        }
        // 审核通过
        if (withdrawVo.getResult() == 1) {
            List<ZjWithdrawOrder> withdrawOrders = withdrawOrderService.getByWithdrawIds(withdrawVo.getIds());
            List<ZjWorkOrder> updateOrderList = new ArrayList<>();
            ZjWorkOrder order = null;
            List<WorkLogVo> logVos = new ArrayList<>();
            for (ZjWithdrawOrder withdrawOrder : withdrawOrders) {
                order = new ZjWorkOrder();
                order.setId(withdrawOrder.getWorkId());
                order.setSettlementStatus(WorkConstant.WORK_SETTLEMENT_STATUS_2);
                updateOrderList.add(order);
                logVos.add(new WorkLogVo(loginInfo, withdrawOrder.getWorkId(), "审核提现", "审核结果：已通过，等待打款；备注：" + withdrawVo.getCheckRemark()));
            }
            workOrderService.updateBatchById(updateOrderList);
            WorkServiceLog.saveService(logVos);
        }
        withdrawService.updateBatchById(updateWithdraws);
        FinanceLogService.saveServiceWithdrawLog(withdrawLogVos);
    }

    // 批量完成打款
    @Override
    @Transactional
    public void finishWithdraw(AccounLoginInfo loginInfo, FinishWithdrawVo withdrawVo) {
        // 校验打款人权限;
        Long loginInfoId = loginInfo.getId();
        List<ZjWithdrawSet> zjWithdrawSets = withdrawSetService.getBaseMapper().selectList(new QueryWrapper<ZjWithdrawSet>());
        ZjWithdrawSet zjWithdrawSet = zjWithdrawSets.get(0);
        String withdrawPayEmp = zjWithdrawSet.getWithdrawPayEmp();
        if (withdrawPayEmp==null)throw new NoAuthPayException("没有配置打款人");
        JSONArray jsonArray = JSONArray.parseArray(withdrawPayEmp);
        List<Long> payEmpIds = jsonArray.toJavaList(Long.class);
        if (!payEmpIds.contains(loginInfoId)) throw new NoAuthPayException("没有打款权限");


        // 多个提现单，同时上传凭证，不允许执行
        if (CollectionUtil.isNotEmpty(withdrawVo.getPaths()) && withdrawVo.getIds().size() > 1) {
            Assert.isTrue(false, "批量完成打款不允许上传打款凭证，仅支持单个提现单上传凭证！");
        }
        // 多个提现单，同时上传凭证，不允许执行
        if (CollectionUtil.isNotEmpty(withdrawVo.getPaths()) && withdrawVo.getIds().size() > 1) {
            Assert.isTrue(false, "批量完成打款不允许上传打款凭证，仅支持单个提现单上传凭证！");
        }
        List<ZjWithdraw> withdraws = withdrawService.listByIds(withdrawVo.getIds());
        Assert.notEmpty(withdraws, "打款的提现单不存在：" + withdrawVo.getIds().stream().map(id -> {
            return id.toString();
        }).collect(Collectors.joining("、")));
        List<String> codes = withdraws.stream().filter(f -> f.getStatus() == FinanceConstant.WITHDRAW_STATUS_1).map(ZjWithdraw::getCode).toList();
        Assert.isTrue(CollectionUtil.isEmpty(codes), "当前提现单处于待审核状态，不允许打款：" + String.join("、", codes));
        codes = withdraws.stream().filter(f -> f.getStatus() == FinanceConstant.WITHDRAW_STATUS_3).map(ZjWithdraw::getCode).toList();
        Assert.isTrue(CollectionUtil.isEmpty(codes), "当前提现单已打款完成，不允许重复打款：" + String.join("、", codes));
        codes = withdraws.stream().filter(f -> f.getStatus() == FinanceConstant.WITHDRAW_STATUS_4).map(ZjWithdraw::getCode).toList();
        Assert.isTrue(CollectionUtil.isEmpty(codes), "当前提现单提现失败，不允许打款：" + String.join("、", codes));
        codes = withdraws.stream().filter(f -> f.getStatus() == FinanceConstant.WITHDRAW_STATUS_5).map(ZjWithdraw::getCode).toList();
        Assert.isTrue(CollectionUtil.isEmpty(codes), "当前提现单已驳回，不允许打款：" + String.join("、", codes));

        // 查询申请人所属的服务商
        List<ZjNetwork> networkList = networkService.getNameByIds(withdraws.stream().map(ZjWithdraw::getApplyNetworkId).distinct().toList());
        List<ZjWithdraw> updateWithdraws = new ArrayList<>();
        ZjWithdraw updateWithdraw = null;
        List<WithdrawLogVo> withdrawLogVos = new ArrayList<>();
        for (ZjWithdraw withdraw : withdraws) {
            updateWithdraw = new ZjWithdraw();
            updateWithdraw.setId(withdraw.getId());
            updateWithdraw.setStatus(88);
            updateWithdraws.add(updateWithdraw);
            withdrawLogVos.add(new WithdrawLogVo(loginInfo.getCustAccId(), withdraw.getId(), loginInfo.getName(),
                    networkList.stream().filter(f -> Objects.equals(f.getId(), withdraw.getApplyNetworkId())).map(ZjNetwork::getName).findFirst().orElse(""),
                    "完成打款", withdrawVo.getRemark()));
        }
        List<ZjWithdrawVoucher> withdrawVouchers = new ArrayList<>();
        ZjWithdrawVoucher withdrawVoucher = null;
        for (String path : withdrawVo.getPaths()) {
            withdrawVoucher = new ZjWithdrawVoucher();
            withdrawVoucher.setId(IdWorker.getId());
            withdrawVoucher.setCustAccId(loginInfo.getCustAccId());
            withdrawVoucher.setWithdrawId(withdrawVo.getIds().get(0));
            withdrawVoucher.setPath(path);
            withdrawVouchers.add(withdrawVoucher);
        }
        List<ZjWithdrawOrder> withdrawOrders = withdrawOrderService.getByWithdrawIds(withdrawVo.getIds());
        List<ZjWorkOrder> updateOrderList = new ArrayList<>();
        ZjWorkOrder order = null;
        List<WorkLogVo> logVos = new ArrayList<>();
        for (ZjWithdrawOrder withdrawOrder : withdrawOrders) {
            order = new ZjWorkOrder();
            order.setId(withdrawOrder.getWorkId());
            order.setSettlementStatus(WorkConstant.WORK_SETTLEMENT_STATUS_3);
            updateOrderList.add(order);
            logVos.add(new WorkLogVo(loginInfo, withdrawOrder.getWorkId(), "完成打款", withdrawVo.getRemark()));
        }
        workOrderService.updateBatchById(updateOrderList);
        withdrawService.updateBatchById(updateWithdraws);
        if (CollectionUtil.isNotEmpty(withdrawVouchers)) {
            withdrawVoucherService.saveBatch(withdrawVouchers);
        }
        WorkServiceLog.saveService(logVos);
        FinanceLogService.saveServiceWithdrawLog(withdrawLogVos);
        //打款后，记录进入ZjWithdrawRecord
        zjWithdrawRecordService.saveWithdrawRecord(withdraws,withdrawVo);
    }

    // 导出提现单
    @Override
    public void exportWithdrawToExcel(AccounLoginInfo loginInfo, HttpServletResponse response, WithdrawListSearchVo search) {
        long count = withdrawService.getListCount(loginInfo.getCustAccId(), search);
        Assert.isTrue(count > 0, "没有可导出的提现单数据");
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(response.getOutputStream(), WithdrawExcelVo.class)
                    .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                    .excelType(ExcelTypeEnum.XLSX)
//                    .registerWriteHandler(new ExcelFillCellMergeStrategy(new int[]{0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 1))
                    .build();
        } catch (Exception e) { }

        Integer page = 0;
        Long limit = 500L;
        Long totalPage = count % limit == 0? count / limit : count / limit +1;
        search.setLimit(limit);
        List<WithdrawExtend> withdrawExtendList = null;
        List<WithdrawExcelVo> withdrawExcelVos = new ArrayList<>();
        WithdrawExcelVo vo = null;
        List<ZjNetwork> networkList = null;
//        String network = null;
        while (page < totalPage) {
            page ++;
            search.setPage(Long.valueOf(page));
            withdrawExtendList = withdrawService.getList(loginInfo.getCustAccId(), search);
            withdrawExtendList = withdrawService.getWithdrawOrderList(loginInfo.getCustAccId(), search);
            networkList = networkService.getNameByIds(withdrawExtendList.stream().map(WithdrawExtend::getApplyNetworkId).distinct().toList());
            for (WithdrawExtend withdraw : withdrawExtendList) {
                vo = new WithdrawExcelVo();
                BeanUtil.copyProperties(withdraw, vo);
                vo.setCreateTime(withdraw.getGmtCreate());
                vo.setWorkNo(withdraw.getWorkNoStr());
                vo.setNetwork(networkList.stream().filter(f -> Objects.equals(f.getId(), withdraw.getApplyNetworkId())).findFirst().map(ZjNetwork::getName).orElse(""));
                withdrawExcelVos.add(vo);
            }
            if (withdrawExcelVos.size() == 5000) {
                excelWriter.write(withdrawExcelVos, EasyExcel.write().sheet(page, "No." + page).build());
                withdrawExcelVos.clear();
            }
        }
        if (CollectionUtil.isNotEmpty(withdrawExcelVos)) {
            excelWriter.write(withdrawExcelVos, EasyExcel.write().sheet(page, "No." + page).build());
        }
        try {
            String fieleSuffix = new StringBuilder()
                    .append("filename=")
                    .append("提现单.xlsx").toString();
            // 注：如使用中文，则需要此行代码配置，如仅使用字母，则可要可不要
            String fieleName = new String(fieleSuffix.getBytes(), "ISO-8859-1");
            response.addHeader("Content-Disposition", fieleName);
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            excelWriter.finish();
        } catch (Exception e) {
            ZbManager.log.error("提现单导出异常：" + e.getMessage());
        }
    }

}
